/* Copyright (c) 2004-2024 Peigen.info. All rights reserved. */

package info.peigen.hotpot.business.account.core.service.processor.transfer;

import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import info.peigen.hotpot.business.account.core.domain.account.AccountLog;
import info.peigen.hotpot.business.account.core.domain.account.AccountTransLog;
import info.peigen.hotpot.business.account.core.domain.account.AccountTransfer;
import info.peigen.hotpot.business.account.core.service.processor.base.AbstractAccountServiceProcessor;
import info.peigen.hotpot.business.account.facade.order.trans.TransferOrder;
import info.peigen.hotpot.common.core.lang.money.Money;
import info.peigen.hotpot.common.core.util.IdUtil;
import info.peigen.hotpot.common.service.base.processor.ProcessorServiceContext;
import org.noear.solon.annotation.Component;

import java.util.Map;

import static info.peigen.hotpot.business.account.facade.enums.AccountFeeAction.Free;


/**
 * <b>(TransferAccountProcessor)</b>
 *
 * @author Peigen
 * @version 1.0.0
 * @since 2022/5/27
 */
@Component
public class TransferAccountProcessor extends AbstractAccountServiceProcessor {
    @Override
    public Integer level() {
        return 20;
    }

    @Override
    public void execute(ProcessorServiceContext serviceContext) {
        // 账户操作
        AccountTransfer transfer = (AccountTransfer) serviceContext.getDomain();

        switch (transfer.getTransCode()) {
            case Deposit:
                deposit(serviceContext);
                break;
            case Withdraw:
                withdraw(serviceContext);
                break;
            case Transfer:
                transfer(serviceContext);
                break;
            default:
        }
    }

    /** 客户充值，联动备付金 */
    private void deposit(ProcessorServiceContext serviceContext) {
        TransferOrder   order             = (TransferOrder) serviceContext.getOrder();
        AccountTransfer transfer          = (AccountTransfer) serviceContext.getDomain();
        Money           depositAmount     = transfer.getTransAmount();
        Money           payeeBalance      = new Money(transfer.getPayeeAccount().getBalance());
        Money           provisionsBalance = new Money(transfer.getProvisionsAccount().getBalance());
        // 1. 账户操作
        // 1.1 收款账户[资金增加]
        transfer.getPayeeAccount().income(depositAmount);
        // 1.2 对应备付金账户[资金增加]
        transfer.getProvisionsAccount().income(depositAmount);

        // 2. 账务记录
        String transLogId = IdUtil.id();
        // 2.1 收款账户账务记录,同时记录资金来源
        AccountLog payeeAccountLog = AccountLog.income(transfer.getPayeeAccount(), payeeBalance, depositAmount, transLogId, transfer.getTradeId(), transfer.getSettleTime(), transfer.getTransMemo());
        // 2.2 备付金账户账务记录,同时记录资金来源与哪张收款卡,便于日后对账
        AccountLog provisionsAccountLog = AccountLog.income(transfer.getProvisionsAccount(), provisionsBalance, depositAmount, transLogId, transfer.getTradeId(), transfer.getSettleTime(), transfer.getTransMemo());
        transfer.getAccountLogs().addAll(Lists.newArrayList(payeeAccountLog, provisionsAccountLog));

        // 3. 收费
        fee(serviceContext);

        // 3. 账务交易记录
        AccountTransLog accountTransLog;
        if (ObjectUtil.isNull(order.getFeeOrderInfo()) || order.getFeeOrderInfo().getAction() == Free) {
            accountTransLog = AccountTransLog.depositNoFee(payeeAccountLog, transfer.getTransAmount());
        } else {
            AccountLog feePayerAccountLog = (AccountLog) serviceContext.getExtend().get("feePayerAccountLog");
            AccountLog feePayeeAccountLog = (AccountLog) serviceContext.getExtend().get("feePayeeAccountLog");
            accountTransLog = AccountTransLog.deposit(payeeAccountLog, feePayerAccountLog, feePayeeAccountLog, transfer.getTransAmount());

        }
        accountTransLog.setTransLogId(transLogId);
        transfer.setAccountTransLog(accountTransLog);
        serviceContext.getResult().setSuccess();
    }

    /** 客户提现，联动备付金 */
    private void withdraw(ProcessorServiceContext serviceContext) {
        TransferOrder   order             = (TransferOrder) serviceContext.getOrder();
        AccountTransfer transfer          = (AccountTransfer) serviceContext.getDomain();
        Money           withdrawAmount    = transfer.getTransAmount();
        Money           payerBalance      = new Money(transfer.getPayerAccount().getBalance());
        Money           provisionsBalance = new Money(transfer.getProvisionsAccount().getBalance());

        // 1.1 付款账户[资金减少]
        transfer.getPayerAccount().paid(withdrawAmount);
        // 1.2 对应备付金账户[资金减少]
        transfer.getProvisionsAccount().paid(withdrawAmount);

        // 2. 账务记录
        String transLogId = IdUtil.id();
        // 2.1 付款账户账务记录,同时记录资金来源
        AccountLog payerAccountLog = AccountLog.paid(transfer.getPayerAccount(), payerBalance, withdrawAmount, transLogId, transfer.getTradeId(), transfer.getSettleTime(), transfer.getTransMemo());
        // 2.2 备付金账户账务记录,同时记录资金来源与哪张收款卡,便于日后对账
        AccountLog provisionsAccountLog = AccountLog.paid(transfer.getProvisionsAccount(), provisionsBalance, withdrawAmount, transLogId, transfer.getTradeId(), transfer.getSettleTime(), transfer.getTransMemo());
        transfer.getAccountLogs().addAll(Lists.newArrayList(payerAccountLog, provisionsAccountLog));

        // 3. 收费
        fee(serviceContext);

        // 3. 账务交易记录
        AccountTransLog accountTransLog = null;
        if (ObjectUtil.isNull(order.getFeeOrderInfo()) || order.getFeeOrderInfo().getAction() == Free) {
            accountTransLog = AccountTransLog.withdrawNoFee(payerAccountLog, transfer.getTransAmount());
        } else {
            AccountLog feePayerAccountLog = (AccountLog) serviceContext.getExtend().get("feePayerAccountLog");
            AccountLog feePayeeAccountLog = (AccountLog) serviceContext.getExtend().get("feePayeeAccountLog");
            accountTransLog = AccountTransLog.withdraw(payerAccountLog, feePayerAccountLog, feePayeeAccountLog, transfer.getTransAmount());
        }
        accountTransLog.setTransLogId(transLogId);
        transfer.setAccountTransLog(accountTransLog);
        serviceContext.getResult().setSuccess();
    }

    /** 转账，资金在备付金内流动 */
    private void transfer(ProcessorServiceContext serviceContext) {
        TransferOrder   order          = (TransferOrder) serviceContext.getOrder();
        AccountTransfer transfer       = (AccountTransfer) serviceContext.getDomain();
        Money           transferAmount = transfer.getTransAmount();

        // 1.1 付款账户[资金减少]
        transfer.getPayerAccount().paid(transferAmount);
        // 1.2 收款账户[资金增加]
        transfer.getPayeeAccount().income(transferAmount);

        // 2. 账务记录
        String transLogId = IdUtil.id();
        // 2.1 付款账户账务记录,同时记录资金来源
        AccountLog payerAccountLog = AccountLog.paid(transfer.getPayerAccount(), transfer.getHistoryPayerBalance(), transferAmount, transLogId, transfer.getTradeId(), transfer.getSettleTime(), transfer.getTransMemo());
        // 2.2 收款账户账务记录,同时记录资金来源
        AccountLog payeeAccountLog = AccountLog.income(transfer.getPayeeAccount(), transfer.getHistoryPayeeBalance(), transferAmount, transLogId, transfer.getTradeId(), transfer.getSettleTime(), transfer.getTransMemo());
        transfer.getAccountLogs().addAll(Lists.newArrayList(payerAccountLog, payeeAccountLog));

        // 3. 收费
        fee(serviceContext);

        // 4. 账务交易记录
        AccountTransLog accountTransLog;
        if (ObjectUtil.isNull(order.getFeeOrderInfo()) || order.getFeeOrderInfo().getAction() == Free) {
            accountTransLog = AccountTransLog.transNoFee(payerAccountLog, payeeAccountLog, transfer.getTransAmount());
        } else {
            AccountLog feePayerAccountLog = (AccountLog) serviceContext.getExtend().get("feePayerAccountLog");
            AccountLog feePayeeAccountLog = (AccountLog) serviceContext.getExtend().get("feePayeeAccountLog");

            accountTransLog = AccountTransLog.trans(payerAccountLog, payeeAccountLog, feePayerAccountLog, feePayeeAccountLog, transfer.getTransAmount());
        }

        accountTransLog.setTransLogId(transLogId);
        transfer.setAccountTransLog(accountTransLog);
        serviceContext.getResult().setSuccess();
    }

    private void fee(ProcessorServiceContext serviceContext) {
        TransferOrder order = (TransferOrder) serviceContext.getOrder();
        // 0. 无需收费则跳过
        if (ObjectUtil.isNull(order.getFeeOrderInfo()) || order.getFeeOrderInfo().getAction() == Free) {
            return;
        }

        // 1. 账户操作
        AccountTransfer transfer = (AccountTransfer) serviceContext.getDomain();
        // 1.1 付费账户[期初余额]
        Money feePayerBalance = new Money(transfer.getFeePayerAccount().getBalance());
        Money feePayeeBalance = new Money(transfer.getFeePayeeAccount().getBalance());
        // 1.2 收费[付费账户],[资金扣减]
        transfer.getFeePayerAccount().paid(transfer.getFeeAmount());
        // 1.3 收费[收入账户],[资金增加]
        transfer.getFeePayeeAccount().income(transfer.getFeeAmount());

        // 2. 账务记录
        // 2.3 收费[付费账户]账务记录
        AccountLog feePayerAccountLog = AccountLog.feePaid(transfer.getFeePayerAccount(), feePayerBalance, transfer.getFeeAmount(), null, transfer.getTradeId(), transfer.getFeeMemo());
        // 2.4 收费[收入账户]账务记录
        AccountLog feePayeeAccountLog = AccountLog.feeIncome(transfer.getFeePayeeAccount(), feePayeeBalance, transfer.getFeeAmount(), null, transfer.getTradeId(), transfer.getFeeMemo());
        transfer.getAccountLogs().addAll(Lists.newArrayList(feePayerAccountLog, feePayeeAccountLog));
        Map<String, Object> extend = serviceContext.getExtend();
        extend.put("feePayerAccountLog", feePayerAccountLog);
        extend.put("feePayeeAccountLog", feePayeeAccountLog);
    }
}